package com.zhuangjie.generator.generators.code.generator;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.fill.Column;
import lombok.Data;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;

@Data
public class CodeGeneratorBuilder {
    private String outputDir;
    private boolean open;
    private boolean fileOverride;
    private IdType idType;
    private DateType dateType;

    private DBConfig dbConfig;

    private String parentPackage;
    private String controllerPackage;
    private String entityPackage;
    private String servicePackage;
    private String mapperPackage;
    @Data
    public static class DBConfig {
        private String dbUrl;
        private String dbDriverName;
        private String username;
        private String password;
        private DbType dbType;
        private String ip;
        private Integer port;


        public DBConfig(DbType dbType, String dbDriverName, String ip, Integer port, String username, String password) {
            this.dbDriverName = dbDriverName;
            this.username = username;
            this.password = password;
            this.dbType = dbType;

            this.ip = ip;
            this.port = port;
        }

        public DBConfig(String ip, String username, String password) {
            this(ip, 3306, username, password);
        }

        public DBConfig(String ip,Integer port, String username, String password) {
            this(DbType.MYSQL, "com.mysql.cj.jdbc.Driver", ip, port, username, password);
        }

        public void setDBName(String db) {
            this.dbUrl = "jdbc:mysql://" + ip + ":" + port + "/" + db + "?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8";
        }
    }

    public CodeGeneratorBuilder(DBConfig dbConfig, String parentPackage) {
        this.open = true; // 生成后是否打开文件位置
        this.fileOverride = true; // 是否覆盖已存在的文件
        this.idType = IdType.ASSIGN_ID; // ID生成类型
        this.dateType = DateType.TIME_PACK; // 生成的时间使用的时间类型

        this.dbConfig = dbConfig;

        this.parentPackage = parentPackage; // 比如：com.zhuangjie
        this.controllerPackage = "controller";
        this.entityPackage = "entity";
        this.servicePackage = "service";
        this.mapperPackage = "mapper";
    }

    /**
     * 获取临时目录路径
     *
     * @return {@link String}
     */
    private static String getTempDirectoryPath() {
        // 获取系统临时目录路径
        String os = System.getProperty("os.name").toLowerCase();

        if (os.contains("win")) {
            // Windows系统
            return System.getenv("TEMP");
        } else if (os.contains("nix") || os.contains("nux") || os.contains("mac")) {
            // Linux或Mac系统
            return "/tmp";
        } else {
            // 默认情况下，返回Java的默认临时目录路径
            return System.getProperty("java.io.tmpdir");
        }
    }

    private void openFolder(String directoryPath) {
        // 检查当前平台是否支持Desktop类
        if (Desktop.isDesktopSupported()) {
            Desktop desktop = Desktop.getDesktop();

            // 封装目录路径为File对象
            File directory = new File(directoryPath);

            // 检查文件或目录是否存在
            if (directory.exists()) {
                // 使用Desktop类打开目录
                try {
                    desktop.open(directory);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            } else {
                System.out.println("目录不存在");
            }
        } else {
            System.out.println("不支持Desktop类");
        }

    }

    public FastAutoGenerator getGenerator(String author, String moduleName, String db, String ignoreTablePrefix, String... tables) {
        // 构建生成的路径
        LocalDateTime currentDate = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmmss");
        if (this.outputDir == null || this.outputDir.isEmpty())
            this.outputDir = getTempDirectoryPath() + "/CodeGeneratorBuilderFor" + (moduleName.substring(0, 1).toUpperCase() + moduleName.substring(1)) + "Module/" + currentDate.format(formatter);
        File srcFolder = new File(this.outputDir + "/src/main/java");  // 指定源文件生成位置
        File resourceFolder = new File(this.outputDir + "/src/main/resources/mapper"); // 指定xxMapper.xml位置
        if (!srcFolder.exists()) srcFolder.mkdirs();
        if (!resourceFolder.exists()) resourceFolder.mkdirs();
        // 判断是否要打开生成的位置
        if (this.open) openFolder(this.outputDir);
        // 再配置
        this.dbConfig.setDBName(db);
        // 构建生成器
        return FastAutoGenerator.create(this.dbConfig.getDbUrl(), this.dbConfig.getUsername(), this.dbConfig.getPassword())
                .globalConfig(builder -> {
                    // 全局配置
                    builder.author(author)                                      //作者
                            .outputDir(srcFolder.getAbsolutePath())          //生成文件输出路径(写到java目录)
                            .enableSwagger()                                    //开启swagger
                            .commentDate("yyyy-MM-dd")                          //注释日期格式
                            .dateType(this.dateType)                       //设置时间对应类型
                            .disableOpenDir()                                   //生成后不要打开目录()
                            .build();
                })
                .packageConfig(builder -> {
                    // 包配置
                    builder
                            .parent(this.parentPackage)
                            .moduleName(moduleName)
                            .controller(controllerPackage)
                            .service(servicePackage)
                            .serviceImpl(servicePackage + ".impl")
                            .entity(entityPackage)
                            .mapper(mapperPackage)
                            .xml(mapperPackage)
                            .pathInfo(Collections.singletonMap(OutputFile.xml, resourceFolder.getAbsolutePath()))
                            .build();
                })
                .strategyConfig(builder -> {
                    //策略配置
                    // 全局是否开启文件覆盖
                    if (this.fileOverride) {
                        builder.entityBuilder().enableFileOverride(); // 动态是否覆盖已存在文件               //覆盖文件(需谨慎使用)
                        builder.mapperBuilder().enableFileOverride(); // 动态是否覆盖已存在文件               //覆盖文件(需谨慎使用)
                        builder.serviceBuilder().enableFileOverride(); // 动态是否覆盖已存在文件               //覆盖文件(需谨慎使用)
                        builder.controllerBuilder().enableFileOverride(); // 动态是否覆盖已存在文件               //覆盖文件(需谨慎使用)
                    }
                    builder.addTablePrefix(ignoreTablePrefix)                   //需要抵消的表前缀
                            .addInclude(tables)                                 //设置生成需要映射的表名
                            .serviceBuilder()                                   //构建Service层
                            .formatServiceFileName("%sService")                 //业务层接口类命名
                            .formatServiceImplFileName("%sServiceImpl")         //业务层接口实现类命名
                            .entityBuilder()                                    //构建实体类
                            .idType(this.idType)
                            // 自动填充配置(学习自https://blog.csdn.net/qq_53861063/article/details/126900723)
                            .addTableFills(new Column("create_time", FieldFill.INSERT)) //根据数据库字段名适配
                            .addTableFills(new Column("update_time", FieldFill.INSERT_UPDATE))//根据生成实体类的属性名适配
                            .columnNaming(NamingStrategy.underline_to_camel)    //字段名驼峰命名
                            .naming(NamingStrategy.underline_to_camel)          //表名驼峰命名
                            .enableLombok()                                     //添加lombock的getter、setter注解
                            .enableChainModel()                                 //启动链式写法@Accessors(chain = true)
                            // .enableColumnConstant()                             //启动属性转常量功能@FieldNameConstants
                            .logicDeleteColumnName("deleted")                   //逻辑删除字段，标记@TableLogic
                            .enableTableFieldAnnotation()                       //启动字段注解
                            .controllerBuilder()                                //构建Controller类
                            .enableHyphenStyle()                                //映射路径使用连字符格式，而不是驼峰
                            .formatFileName("%sController")                     //Controller类命名
                            .enableRestStyle()                                  //标记@RestController注解
                            .mapperBuilder()                                    //构建mapper接口类
                            // .enableBaseResultMap()                             //生成基本的resultMap
                            // .enableBaseColumnList()                            //生成xml文件中基本查询的片段（<sql id="Base_Column_List">）
                            .formatMapperFileName("%sMapper")                   //Mapper接口类明名
                            .superClass(BaseMapper.class)                       //Mapper接口类集成 BaseMapper
                            .enableMapperAnnotation()                           //标记@Mapper注解
                            .formatXmlFileName("%sMapper")                      //Mapper.xml命名
                            .build();
                });

    }


}
